package org.springblade.modules.admin.task.feishu;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSONObject;
import com.xxl.job.core.context.XxlJobHelper;
import com.xxl.job.core.handler.annotation.XxlJob;
import lombok.extern.slf4j.Slf4j;
import org.springblade.common.enums.FeiShuDocumentEnum;
import org.springblade.core.tool.utils.Func;
import org.springblade.modules.admin.dto.feishu.FeiShuBatchDTO;
import org.springblade.modules.admin.dto.feishu.FeiShuFieldsDTO;
import org.springblade.modules.admin.enums.MaintainPlanContentEnum;
import org.springblade.modules.admin.enums.TaskStatusEnum;
import org.springblade.modules.admin.service.*;
import org.springblade.modules.admin.service.feishu.IFeiShuDocumentService;
import org.springblade.modules.admin.vo.plan.wx.BiWxPlanDetailVo;
import org.springblade.modules.admin.vo.sugar.bi.BILarkRescueBigTableVO;
import org.springblade.modules.admin.vo.sugar.bi.BILarkRescueCountSourceVO;
import org.springblade.modules.admin.vo.sugar.bi.BILarkRescueHealthVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 天雄救援与维修指标相关定时任务
 * @author: Sharry
 * @createTime: 2025-03-26 16:04
 * @version: Version-1.0
 */
@Component
@Slf4j
public class LarkRescueAndFaultIndexJob {

	@Autowired
	private IFeiShuDocumentService feiShuDocumentService;
	@Autowired
	private BuildingService buildingService;
	@Autowired
	private BIService biService;
	@Autowired
	private IElevatorMaintainStatusDayService maintainStatusDayService;
	@Autowired
	private IMaintainMalfunctionWorkService maintainMalfunctionWorkService;
	@Autowired
	private IMaintainMalfunctionRescueService rescueService;

	/**
	 * 按日风险事件指标表
	 * 下午17：00
	 */
	@XxlJob("galaxyDailyRiskEventIndexJob")
	public void galaxyDailyRiskEventIndexJob(){
		XxlJobHelper.handleSuccess("定时任务更新天雄救援故障仪表盘-按日风险事件指标表-[执行]开始");
		try{
			String appToken = FeiShuDocumentEnum.DAILY_RISK_EVENT_INDEX.getAppToken();
			String tableId = FeiShuDocumentEnum.DAILY_RISK_EVENT_INDEX.getTableId();
			// 1. 组装查询条件并查询
			// 开始时间固定 2025-03-01 00:00:00
			Date startDate = DateUtil.parse("2025-03-01 00:00:00");
			Date endDate = new Date();
			log.info("查询时间段：{}-{}",
				DateUtil.format(startDate, "yyyy-MM-dd HH:mm:ss"),
				DateUtil.format(endDate, "yyyy-MM-dd HH:mm:ss"));
			List<Map<String, Object>> maps = biService.selectWxFaultPlanCount(startDate, endDate);
			FeiShuBatchDTO batchDTO = new FeiShuBatchDTO();
			List<FeiShuFieldsDTO> records = new ArrayList<>();
			for (Map<String, Object> m : maps) {
				FeiShuFieldsDTO element = new FeiShuFieldsDTO();
				Map<String, Object> elementMap = new HashMap<>(12);
				elementMap.put("日期",m.get("日期"));
				elementMap.put("当日新增风险事件",m.get("当日新增风险事件"));
				elementMap.put("截止当前待处理事件",m.get("截止当前待处理事件"));
				elementMap.put("截止当前处理中事件",m.get("截止当前处理中事件"));
				elementMap.put("截止当前关闭超时事件（非已关闭）",m.get("截止当前关闭超时事件（非已关闭）"));
				elementMap.put("截止当前关闭事件",m.get("截止当前已关闭事件"));
				element.setFields(elementMap);
				records.add(element);
			}
			batchDTO.setRecords(records);
			// 3. 覆盖表格，并发送消息
			List<JSONObject> deleteObjects = feiShuDocumentService.commandQueryBatch(appToken, tableId, null);
			// 遍历并获取 jsonObjects 的 封装成 FeiShuBatchDTO 对象
			List<String> r = new ArrayList<>();
			deleteObjects.forEach(j -> r.add(j.getString("record_id")));
			FeiShuBatchDTO deleteFeiShuBatchDTO = new FeiShuBatchDTO();
			deleteFeiShuBatchDTO.setRecords(r);
			// 直接覆盖
			feiShuDocumentService.commandDeleteBatchLimit(appToken, tableId, deleteFeiShuBatchDTO);
			// 新增
			String result = feiShuDocumentService.commandAddBatchLimit(appToken, tableId, batchDTO);
			result = "定时任务更新天雄救援故障仪表盘-风险事件指标表" + result;
			// 发送消息
			feiShuDocumentService.commandSendGroupMessage(appToken,tableId,result);
			XxlJobHelper.handleSuccess("定时任务更新天雄救援故障仪表盘-按日风险事件指标表-[执行]成功");
		}catch (Exception e){
			XxlJobHelper.handleSuccess("定时任务更新天雄救援故障仪表盘-按日风险事件指标表-[执行]失败"+e);
		}
	}

	/**
	 * 风险事件明细表
	 * 每日凌晨
	 */
	@XxlJob("galaxyRiskEventDetailJob")
	public void galaxyRiskEventDetailJob(){
		XxlJobHelper.handleSuccess("定时任务更新天雄救援故障仪表盘-风险事件明细表-[执行]开始");
		try{
			String appToken = FeiShuDocumentEnum.DAILY_RISK_EVENT_DETAIL.getAppToken();
			String tableId = FeiShuDocumentEnum.DAILY_RISK_EVENT_DETAIL.getTableId();
			// 1. 组装查询条件并查询
			// 结束时间是上一周最后一天的的23:59:59
			Calendar calendar = Calendar.getInstance();
			Date today = new Date();
            // 开始时间是前5周的周一00:00:00
			calendar.add(Calendar.WEEK_OF_MONTH, -4);
			calendar.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
			calendar.set(Calendar.HOUR_OF_DAY, 0);
			calendar.set(Calendar.MINUTE, 0);
			calendar.set(Calendar.SECOND, 0);
			Date startDate = calendar.getTime();
			log.info("查询时间段：{}-{}",
				DateUtil.format(startDate, "yyyy-MM-dd HH:mm:ss"),
				DateUtil.format(today, "yyyy-MM-dd HH:mm:ss"));
			List<Map<String, Object>> maps = biService.selectWxFaultPlanList(startDate, today);
			// 2. 组装数据并发送
			FeiShuBatchDTO batchDTO = new FeiShuBatchDTO();
			List<FeiShuFieldsDTO> records = new ArrayList<>();
			for (Map<String, Object> m : maps) {
				FeiShuFieldsDTO element = new FeiShuFieldsDTO();
				Map<String, Object> elementMap = new HashMap<>(12);
				elementMap.put("故障风险等级",m.get("故障风险等级"));
				elementMap.put("故障风险标签",m.get("故障风险标签"));
				elementMap.put("风险预警时间",m.get("风险预警时间"));
				elementMap.put("电梯编号",m.get("电梯编号"));
				elementMap.put("电梯名称",m.get("电梯名称"));
				elementMap.put("项目名称",m.get("项目名称"));
				elementMap.put("所属维保组",m.get("所属维保组"));
				elementMap.put("风险关闭时长要求",m.get("风险关闭时长要求"));
				elementMap.put("处理建议",m.get("处理建议"));
				elementMap.put("风险处理进展",m.get("风险处理进展"));
				elementMap.put("风险关闭时间",m.get("风险关闭时间"));
				elementMap.put("风险关闭是否超时",m.get("风险关闭是否超时"));
				elementMap.put("风险处理人",m.get("风险处理人"));
				elementMap.put("是否调度技术支持/专家",m.get("是否调度技术支持/专家"));
				elementMap.put("技术支持/专家姓名",m.get("技术支持/专家姓名"));
				elementMap.put("风险关联工单ID",m.get("风险关联电梯ID"));

				element.setFields(elementMap);
				records.add(element);
			}
			batchDTO.setRecords(records);
			// 3. 覆盖表格，并发送消息
			List<JSONObject> deleteObjects = feiShuDocumentService.commandQueryBatch(appToken, tableId, null);
			// 遍历并获取 jsonObjects 的 封装成 FeiShuBatchDTO 对象
			List<String> r = new ArrayList<>();
			deleteObjects.forEach(j -> r.add(j.getString("record_id")));
			FeiShuBatchDTO deleteFeiShuBatchDTO = new FeiShuBatchDTO();
			deleteFeiShuBatchDTO.setRecords(r);
			// 直接覆盖
			feiShuDocumentService.commandDeleteBatchLimit(appToken, tableId, deleteFeiShuBatchDTO);
			// 新增
			String result = feiShuDocumentService.commandAddBatchLimit(appToken, tableId, batchDTO);
			result = "定时任务更新天雄救援故障仪表盘-风险事件明细表" + result;
			// 发送消息
			feiShuDocumentService.commandSendGroupMessage(appToken,tableId,result);

			XxlJobHelper.handleSuccess("定时任务更新天雄救援故障仪表盘-风险事件明细表-[执行]成功");
		}catch (Exception e){
			XxlJobHelper.handleSuccess("定时任务更新天雄救援故障仪表盘-风险事件明细表-[执行]失败"+e);
		}
	}

	/**
	 * 按周维修健康指标表
	 */
	@XxlJob("galaxyWeeklyRepairHealthIndexJob")
	public void galaxyWeeklyRepairHealthIndexJob(){
		XxlJobHelper.handleSuccess("定时任务更新天雄救援故障仪表盘-按周维修健康指标表-[执行]开始");
		try{
			String appToken = FeiShuDocumentEnum.WEEKLY_REPAIR_HEALTH_INDEX.getAppToken();
			String tableId = FeiShuDocumentEnum.WEEKLY_REPAIR_HEALTH_INDEX.getTableId();
			// 1. 组装数据并查询
			// 结束时间是上一周最后一天的的23:59:59
			Calendar calendar = Calendar.getInstance();
			Date today = new Date();
			calendar.setTime(today);
			calendar.add(Calendar.WEEK_OF_MONTH, -1);
			calendar.set(Calendar.DAY_OF_WEEK, calendar.getActualMaximum(Calendar.DAY_OF_WEEK));
			calendar.set(Calendar.HOUR_OF_DAY, 23);
			calendar.set(Calendar.MINUTE, 59);
			calendar.set(Calendar.SECOND, 59);
			Date endDate = calendar.getTime();
			// 开始时间是前5周的周一00:00:00
			calendar.add(Calendar.WEEK_OF_MONTH, -4);
			calendar.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
			calendar.set(Calendar.HOUR_OF_DAY, 0);
			calendar.set(Calendar.MINUTE, 0);
			calendar.set(Calendar.SECOND, 0);
			Date startDate = calendar.getTime();
			log.info("查询时间段：{}-{}",
				DateUtil.format(startDate, "yyyy-MM-dd HH:mm:ss"),
				DateUtil.format(endDate, "yyyy-MM-dd HH:mm:ss"));
			// 按周
			Integer dateType = 2;
			List<List<String>> rows = new ArrayList<>();
			List<Map<String, String>> mapList = biService.downWxHealthIndexExcelForLark(startDate, endDate, dateType, rows);
			sendRepairHealthTableData(mapList, appToken, tableId);
			XxlJobHelper.handleSuccess("定时任务更新天雄救援故障仪表盘-按周维修健康指标表-[执行]成功");
		}catch (Exception e){
			XxlJobHelper.handleSuccess("定时任务更新天雄救援故障仪表盘-按周维修健康指标表-[执行]失败"+e);
		}
	}

	/**
	 * 按月维修健康指标表
	 */
	@XxlJob("galaxyMonthlyRepairHealthIndexJob")
	public void galaxyMonthlyRepairHealthIndexJob(){
		XxlJobHelper.handleSuccess("定时任务更新天雄救援故障仪表盘-按月维修健康指标表-[执行]开始");
		try{
			String appToken = FeiShuDocumentEnum.MONTHLY_REPAIR_HEALTH_INDEX.getAppToken();
			String tableId = FeiShuDocumentEnum.MONTHLY_REPAIR_HEALTH_INDEX.getTableId();
			// 1. 组装查询条件并查询
			List<List<String>> rows = new ArrayList<>();
			Integer dateType = 3;
			// 结束时间是上一个月的最后一天的23:59:59
			Calendar calendar = Calendar.getInstance();
			Date today = new Date();
			calendar.setTime(today);
			calendar.add(Calendar.MONTH, -1);
			calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMaximum(Calendar.DAY_OF_MONTH));
			calendar.set(Calendar.HOUR_OF_DAY, 23);
			calendar.set(Calendar.MINUTE, 59);
			calendar.set(Calendar.SECOND, 59);
			Date endDate = calendar.getTime();
			// 开始时间是前4月的第一天00:00:00
			calendar.add(Calendar.MONTH, -4);
			calendar.set(Calendar.DAY_OF_MONTH, 1);
			calendar.set(Calendar.HOUR_OF_DAY, 0);
			calendar.set(Calendar.MINUTE, 0);
			calendar.set(Calendar.SECOND, 0);
			Date startDate = calendar.getTime();
			log.info("查询时间段：{}-{}",
				DateUtil.format(startDate, "yyyy-MM-dd HH:mm:ss"),
				DateUtil.format(endDate, "yyyy-MM-dd HH:mm:ss"));
			List<Map<String, String>> mapList = biService.downWxHealthIndexExcelForLark(startDate, endDate, dateType, rows);
			sendRepairHealthTableData(mapList, appToken, tableId);
			XxlJobHelper.handleSuccess("定时任务更新天雄救援故障仪表盘-按月维修健康指标表-[执行]成功");
		}catch (Exception e){
			XxlJobHelper.handleSuccess("定时任务更新天雄救援故障仪表盘-按月维修健康指标表-[执行]失败"+e);
		}
	}

	/**
	 * 维修工单明细
	 */
	@XxlJob("galaxyRepairPlanDetailJob")
	public void galaxyRepairPlanDetailJob(){
		XxlJobHelper.handleSuccess("定时任务更新天雄救援故障仪表盘-维修工单明细表-[执行]开始");
		try{
			String appToken = FeiShuDocumentEnum.REPAIR_PLAN_DETAIL.getAppToken();
			String tableId = FeiShuDocumentEnum.REPAIR_PLAN_DETAIL.getTableId();
			Date endDate = new Date();
			// 使用Calendar计算往前推5个月,该月第一天的00:00:00
			Calendar calendar = Calendar.getInstance();
			calendar.setTime(endDate);
			calendar.add(Calendar.MONTH, -5);
			calendar.set(Calendar.DAY_OF_MONTH, 1);
			calendar.set(Calendar.HOUR_OF_DAY, 0);
			calendar.set(Calendar.MINUTE, 0);
			calendar.set(Calendar.SECOND, 0);
			Date startDate = calendar.getTime();
			log.info("查询时间段：{}-{}",
				DateUtil.format(startDate, "yyyy-MM-dd HH:mm:ss"),
				DateUtil.format(endDate, "yyyy-MM-dd HH:mm:ss"));
			List<BiWxPlanDetailVo> list = maintainMalfunctionWorkService.getBiWxPlanDetailList(startDate, endDate);
			list = list.stream().filter(l -> l.getStatus() == 2 || l.getStatus() == 3 || l.getStatus() == 4).collect(Collectors.toList());
			// 2. 数据封装、处理
			FeiShuBatchDTO batchDTO = new FeiShuBatchDTO();
			List<FeiShuFieldsDTO> records = new ArrayList<>();
			for (BiWxPlanDetailVo m : list) {
				FeiShuFieldsDTO element = new FeiShuFieldsDTO();
				Map<String, Object> elementMap = new HashMap<>(30);
				elementMap.put("工单编号", m.getPlanId());
				Date planCreateTime = m.getPlanCreateTime();
				if(!Func.isNull(planCreateTime)){
					// 所属周描述
					elementMap.put("所属周",getWeekDesc(planCreateTime));
					// 所属月描述
					elementMap.put("所属月",getMonthDesc(planCreateTime));
					// 工单创建时间
					elementMap.put("工单创建时间",planCreateTime.getTime());
				}
				String provinceName = m.getProvinceName();
				if(Func.isNotBlank(provinceName)){
					elementMap.put("省",provinceName);
				}
				String cityName = m.getCityName();
				if(Func.isNotBlank(cityName)){
					elementMap.put("市",cityName);
				}
				String adName = m.getAdName();
				if (Func.isNotBlank(adName)){
					elementMap.put("区",adName);
				}
				Integer planFrom = Convert.toInt(m.getPlanFrom(), -1);
				if (!Func.isNull(planFrom)) {
					//任务来源: 1: 物业端, 2: 微信, 3: 服务电话, 4: 系统派单, 5: 维保端，6: 游客, 7: web, 8: 梯联网
					if (planFrom == 1) {
						elementMap.put("故障来源", "物业端");
					} else if (planFrom == 2) {
						elementMap.put("故障来源", "微信");
					} else if (planFrom == 3) {
						elementMap.put("故障来源", "服务电话");
					} else if (planFrom == 4) {
						elementMap.put("故障来源", "系统派单");
					} else if (planFrom == 5) {
						elementMap.put("故障来源", "维保端");
					} else if (planFrom == 6) {
						elementMap.put("故障来源", "游客");
					} else if (planFrom == 7) {
						elementMap.put("故障来源", "web");
					} else if (planFrom == 8) {
						elementMap.put("故障来源", "梯联网");
					}
				}
				elementMap.put("工单类型","维修");
				elementMap.put("报障状态",Convert.toInt(m.getElevatorStop(), -1) == 1 ? "正常" : "停梯");
				elementMap.put("实时运行状态",Convert.toInt(m.getNowElevatorStop(), -1) == 1 ? "正常" : "停梯");
				elementMap.put("工单状态",Convert.toStr(TaskStatusEnum.getTaskName(2, m.getStatus()),"/"));
				elementMap.put("电梯编号",Convert.toStr(m.getPrivateNum(), "/"));
				elementMap.put("电梯位置（梯号）",Convert.toStr(m.getElevatorAddress(), "/"));
				elementMap.put("所属维保组",Convert.toStr(m.getPrincipalDeptNames(), "/"));
				elementMap.put("所属责任人",Convert.toStr(m.getPrincipalUserNames(), "/"));
				Integer type = Convert.toInt(m.getBuildingType(), -1);
				if (!Func.isNull(type)) {
					if (type == 1) {
						elementMap.put("项目类型", "小区");
					} else if (type == 2) {
						elementMap.put("项目类型", "别墅");
					} else if (type == 3) {
						elementMap.put("项目类型", "商超");
					} else if (type == 4) {
						elementMap.put("项目类型", "酒店/民宿");
					} else if (type == 5) {
						elementMap.put("项目类型", "学校");
					} else if (type == 6) {
						elementMap.put("项目类型", "医院");
					} else if (type == 7) {
						elementMap.put("项目类型","工厂");
					} else if (type == 8) {
						elementMap.put("项目类型","其他");
					} else if (type == 9) {
						elementMap.put("项目类型","办公楼");
					} else if (type == 10) {
						elementMap.put("项目类型","政府单位");
					} else if (type == 11) {
						elementMap.put("项目类型","公共设施");
					} else if (type == 12) {
						elementMap.put("项目类型","出租房");
					}
				}
				Date allocateTime = m.getAllocateTime();
				if (!Func.isNull(allocateTime)) {
					elementMap.put("调度时间", allocateTime.getTime());
				}
				Date firstSignTime = m.getFirstSignTime();
				if (!Func.isNull(firstSignTime)) {
					elementMap.put("第1次签到时间",firstSignTime.getTime());
				}
				Date endSignOutTime = m.getEndSignOutTime();
				if (!Func.isNull(endSignOutTime)) {
					elementMap.put("最后1次签退时间",endSignOutTime.getTime());
				}
				if (m.getStatus() != 4) {
					elementMap.put("工单调度人员",Convert.toStr(m.getRealPlanUserNames(),"/"));
				} else {
					elementMap.put("工单调度人员",Convert.toStr(m.getPlanUserNames(),"/"));
				}
				elementMap.put("预计到达时长(分)",Convert.toStr(m.getPlanArriveMinute(),"/"));
				elementMap.put("实际到达耗时（分）",Convert.toStr(m.getRealArriveHour(), "/"));
				if (m.getStatus() == 4) {
					elementMap.put("工单实际执行人",Convert.toStr(m.getRealPlanUserNames()));
					elementMap.put("实际执行人数",Convert.toStr((m.getRealPlanUserNames().split(",").length)));
				}
				if (!Func.isNull(m.getFinishPlanTime())) {
					elementMap.put("工单完成时间",m.getFinishPlanTime().getTime());
				}
				elementMap.put("作业工时(小时)",Convert.toStr(m.getWorkWHour(), "0"));
				elementMap.put("作业耗时(小时)",Convert.toStr(m.getWorkHHour(), "0"));
				elementMap.put("完成工时(小时)",Convert.toStr(m.getWorkAllHour(), "0"));
				if(!Func.isNull(m.getBuildingId())) {
					elementMap.put("项目ID", m.getBuildingId());
				}
				elementMap.put("项目名称",Convert.toStr(m.getBuildingName(),"/"));
				elementMap.put("项目要求到达时长（分）",Convert.toStr(m.getMalfunctionWorkArrivalTime(), "/"));
				if(!Func.isNull(m.getPlanCreateTime()) && !Func.isNull(m.getFinishPlanTime())){
					long diff = m.getFinishPlanTime().getTime() - m.getPlanCreateTime().getTime();
					// 将diff转换为double小时，保留2位小数
					double hour = (double) diff / (1000 * 60 * 60);
					elementMap.put("面向客户完成耗时(小时)",hour);
				}
				element.setFields(elementMap);
				records.add(element);
			}
			batchDTO.setRecords(records);
			// 3. 覆盖表格，并发送消息
			List<JSONObject> deleteObjects = feiShuDocumentService.commandQueryBatch(appToken, tableId, null);
			// 遍历并获取 jsonObjects 的 封装成 FeiShuBatchDTO 对象
			List<String> r = new ArrayList<>();
			deleteObjects.forEach(j -> r.add(j.getString("record_id")));
			FeiShuBatchDTO deleteFeiShuBatchDTO = new FeiShuBatchDTO();
			deleteFeiShuBatchDTO.setRecords(r);
			// 直接覆盖
			feiShuDocumentService.commandDeleteBatchLimit(appToken, tableId, deleteFeiShuBatchDTO);
			// 新增
			String result = feiShuDocumentService.commandAddBatchLimit(appToken, tableId, batchDTO);
			result = "定时任务更新天雄救援故障仪表盘-维修工单明细表" + result;
			// 发送消息
			feiShuDocumentService.commandSendGroupMessage(appToken,tableId,result);
			XxlJobHelper.handleSuccess("定时任务更新天雄救援故障仪表盘-维修工单明细表-[执行]成功");
		}catch (Exception e){
			XxlJobHelper.handleSuccess("定时任务更新天雄救援故障仪表盘-维修工单明细表-[执行]失败"+e);
		}
	}

	/**
	 * 按周救援健康指标表
	 */
	@XxlJob("galaxyWeeklyRescueHealthIndexJob")
	public void galaxyWeeklyRescueHealthIndexJob(){
		XxlJobHelper.handleSuccess("定时任务更新天雄救援故障仪表盘-按周救援健康指标表-[执行]开始");
		try{
			String appToken = FeiShuDocumentEnum.WEEKLY_RESCUE_HEALTH_INDEX.getAppToken();
			String tableId = FeiShuDocumentEnum.WEEKLY_RESCUE_HEALTH_INDEX.getTableId();
			// 1. 组装数据并查询
			// 结束时间是上一周最后一天的的23:59:59
			Calendar calendar = Calendar.getInstance();
			Date today = new Date();
			calendar.setTime(today);
			calendar.add(Calendar.WEEK_OF_MONTH, -1);
			calendar.set(Calendar.DAY_OF_WEEK, calendar.getActualMaximum(Calendar.DAY_OF_WEEK));
			calendar.set(Calendar.HOUR_OF_DAY, 23);
			calendar.set(Calendar.MINUTE, 59);
			calendar.set(Calendar.SECOND, 59);
			Date endDate = calendar.getTime();
			// 开始时间是前5周的周一00:00:00
			calendar.add(Calendar.WEEK_OF_MONTH, -4);
			calendar.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
			calendar.set(Calendar.HOUR_OF_DAY, 0);
			calendar.set(Calendar.MINUTE, 0);
			calendar.set(Calendar.SECOND, 0);
			Date startDate = calendar.getTime();
			log.info("查询时间段：{}-{}",
				DateUtil.format(startDate, "yyyy-MM-dd HH:mm:ss"),
				DateUtil.format(endDate, "yyyy-MM-dd HH:mm:ss"));
			// 按周
			Integer dateType = 2;
			List<BILarkRescueHealthVO> exportData = getExportData(startDate, endDate, dateType);
			// 2. 数据封装、处理
			sendRescueHealthTableData(exportData, appToken, tableId);
			XxlJobHelper.handleSuccess("定时任务更新天雄救援故障仪表盘-按周救援健康指标表-[执行]成功");
		}catch (Exception e){
			XxlJobHelper.handleSuccess("定时任务更新天雄救援故障仪表盘-按周救援健康指标表-[执行]失败"+e);
		}
	}

	/**
	 * 按月救援健康指标表
	 *
	 */
	@XxlJob("galaxyMonthlyRescueHealthIndexJob")
	public void galaxyMonthlyRescueHealthIndexJob(){
		XxlJobHelper.handleSuccess("定时任务更新天雄救援故障仪表盘-按月救援健康指标表-[执行]开始");
		try{
			String appToken = FeiShuDocumentEnum.MONTHLY_RESCUE_HEALTH_INDEX.getAppToken();
			String tableId = FeiShuDocumentEnum.MONTHLY_RESCUE_HEALTH_INDEX.getTableId();
			// 1. 组装数据并查询
			// 结束时间是上一个月的最后一天的23:59:59
			Calendar calendar = Calendar.getInstance();
			Date today = new Date();
			calendar.setTime(today);
			calendar.add(Calendar.MONTH, -1);
			calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMaximum(Calendar.DAY_OF_MONTH));
			calendar.set(Calendar.HOUR_OF_DAY, 23);
			calendar.set(Calendar.MINUTE, 59);
			calendar.set(Calendar.SECOND, 59);
			Date endDate = calendar.getTime();
			// 开始时间是前4月的第一天00:00:00
			calendar.add(Calendar.MONTH, -4);
			calendar.set(Calendar.DAY_OF_MONTH, 1);
			calendar.set(Calendar.HOUR_OF_DAY, 0);
			calendar.set(Calendar.MINUTE, 0);
			calendar.set(Calendar.SECOND, 0);
			Date startDate = calendar.getTime();
			log.info("查询时间段：{}-{}",
				DateUtil.format(startDate, "yyyy-MM-dd HH:mm:ss"),
				DateUtil.format(endDate, "yyyy-MM-dd HH:mm:ss"));
			// 按月
            Integer dateType = 3;
			List<BILarkRescueHealthVO> exportData = getExportData(startDate, endDate, dateType);
			// 2. 数据封装、处理
			sendRescueHealthTableData(exportData, appToken, tableId);
			XxlJobHelper.handleSuccess("定时任务更新天雄救援故障仪表盘-按月救援健康指标表-[执行]成功");
		}catch (Exception e){
			XxlJobHelper.handleSuccess("定时任务更新天雄救援故障仪表盘-按月救援健康指标表-[执行]失败"+e);
		}
	}

	/**
	 * 救援工单明细表
	 * 当天 算起往前推90天的数据
	 * 每天 17:30 前多次执行，覆盖
	 */
	@XxlJob("galaxyRescuePlanDetailJob")
	public void galaxyRescuePlanDetailJob(){
		XxlJobHelper.handleSuccess("定时任务更新天雄救援故障仪表盘-救援工单明细表-[执行]开始");
		try{
			// 0. 确定表格appToken及id
			String appToken = FeiShuDocumentEnum.RESCUE_PLAN_DETAIL.getAppToken();
			String tableId = FeiShuDocumentEnum.RESCUE_PLAN_DETAIL.getTableId();
			// 1. 组装数据并查询
			// 获取当前时间
			Date endDate = new Date();
			// 使用Calendar计算往前推5个月,该月第一天的00:00:00
			Calendar calendar = Calendar.getInstance();
			calendar.setTime(endDate);
			calendar.add(Calendar.MONTH, -5);
			calendar.set(Calendar.DAY_OF_MONTH, 1);
			calendar.set(Calendar.HOUR_OF_DAY, 0);
			calendar.set(Calendar.MINUTE, 0);
			calendar.set(Calendar.SECOND, 0);
			Date startDate = calendar.getTime();
			log.info("查询时间段：{}-{}",
				DateUtil.format(startDate, "yyyy-MM-dd HH:mm:ss"),
				DateUtil.format(endDate, "yyyy-MM-dd HH:mm:ss"));
			List<BILarkRescueBigTableVO> dataSourceList = buildingService.getLarkRescueBigTable(startDate, endDate);
			// 2.1 数据处理
			dataSourceList.forEach( r -> {
				// 将 sendUseTime 秒值转换成分钟
				Integer sendUseTime = r.getSendUseTime();
				if(!Func.isNull(sendUseTime)){
					double sendUseTimeMinuteValue = ((double) sendUseTime / 60);
					double sendUseTimeMinute = getRounder(sendUseTimeMinuteValue);
					r.setSendUseTimeMinute(sendUseTimeMinute);
				}
				// 将毫秒值转换成分钟，以下同理
				Long arriveDuration = r.getArriveDuration();
				if(!Func.isNull(arriveDuration)){
					double arriveUseTimeMinuteValue = ((double) arriveDuration / 60000);
					double arriveUseTimeMinute = getRounder(arriveUseTimeMinuteValue);
					r.setArriveUseTime(arriveUseTimeMinute);
				}

				Double rescueUseTime = r.getRescueTime();
				if(!Func.isNull(rescueUseTime)){
					double rescueUseTimeMinuteValue = (rescueUseTime / 60);
					double rescueUseTimeMinute = getRounder(rescueUseTimeMinuteValue);
					r.setRescueTime(rescueUseTimeMinute);
				}

				Long workMill = r.getWorkMill();
				if(!Func.isNull(workMill)){
					double workMillValue = ((double) workMill / 60000);
					double workMinute = getRounder(workMillValue);
					r.setWorkMinute(workMinute);
				}

				Integer planStatus = r.getPlanStatus();
				if(!Func.isNull(planStatus)){
					r.setPlanStatusDesc(TaskStatusEnum.getTaskName(MaintainPlanContentEnum.MAINTAIN_KR.getId(), planStatus));
				}
			});
			// 2.2 数据封装
			FeiShuBatchDTO batchDTO = new FeiShuBatchDTO();
			List<FeiShuFieldsDTO> records = new ArrayList<>();
			for (BILarkRescueBigTableVO m : dataSourceList) {
				FeiShuFieldsDTO element = new FeiShuFieldsDTO();
				Map<String, Object> elementMap = new HashMap<>(30);
				elementMap.put("任务编号", m.getPlanId());
				Date reportTime = m.getReportTime();
				if(!Func.isNull(reportTime)){
					// 所属周描述
					elementMap.put("所属周",getWeekDesc(reportTime));
					// 所属月描述
					elementMap.put("所属月",getMonthDesc(reportTime));
					// 报警时间
					elementMap.put("报警时间", reportTime.getTime());
				}
				// 一下是接下来每个字段的put入map，级别都是判断非空，很无聊，but没有办法
				String elevatorId = m.getElevatorId();
				if(Func.isNotBlank(elevatorId)){
					elementMap.put("电梯ID", elevatorId);
				}
				String elevatorAddress = m.getElevatorAddress();
				if(Func.isNotBlank(elevatorAddress)){
					elementMap.put("电梯位置", elevatorAddress);
				}
				String buildingName = m.getBuildingName();
				if(Func.isNotBlank(buildingName)){
					elementMap.put("项目名称", buildingName);
				}
				String buildingType = m.getBuildingType();
				if(Func.isNotBlank(buildingType)){
					elementMap.put("项目类型", buildingType);
				}
				String province = m.getProvince();
				if(Func.isNotBlank(province)){
					elementMap.put("省", province);
				}
				String city = m.getCity();
				if(Func.isNotBlank(city)){
					elementMap.put("市", city);
				}
				String ad = m.getAd();
				if(Func.isNotBlank(ad)){
					elementMap.put("区", ad);
				}
				String requireTime = m.getRequireTime();
				if(Func.isNotBlank(requireTime)){
					elementMap.put("项目要求到达时长", requireTime);
				}
				String planUsers = m.getPlanUsers();
				if(Func.isNotBlank(planUsers)){
					elementMap.put("任务指派", planUsers);
				}
				String exeUsers = m.getExeUsers();
				if(Func.isNotBlank(exeUsers)){
					elementMap.put("实际执行人", exeUsers);
				}
				String userGroups = m.getUserGroups();
				if(Func.isNotBlank(userGroups)){
					elementMap.put("人员所在维保组", userGroups);
				}
				String elevatorMaintainGroup = m.getElevatorMaintainGroup();
				if(Func.isNotBlank(elevatorMaintainGroup)) {
					elementMap.put("电梯所在维保组", elevatorMaintainGroup);
				}
				String reportName = m.getReportName();
				if(Func.isNotBlank(reportName)){
					elementMap.put("报警人", reportName);
				}
				String reportSource = m.getReportSource();
				if(Func.isNotBlank(reportSource)){
					elementMap.put("报警来源", reportSource);
				}
				Date sendTime = m.getSendTime();
				if(!Func.isNull(sendTime)){
					elementMap.put("人员指派时间", sendTime.getTime());
				}
				Date firstSignTime = m.getFirstSignTime();
				if(!Func.isNull(firstSignTime)){
					elementMap.put("签到时间（第一次）", firstSignTime.getTime());
				}
				Date lastSignTime = m.getLastSignTime();
				if(!Func.isNull(lastSignTime)){
					elementMap.put("签退时间（最后1次）", lastSignTime.getTime());
				}
				Date rescueFinishTime = m.getRescueFinishTime();
				if(!Func.isNull(rescueFinishTime)){
					elementMap.put("救援完成时间", rescueFinishTime.getTime());
				}
				Double sendUseTimeMinute = m.getSendUseTimeMinute();
				if(!Func.isNull(sendUseTimeMinute)){
					elementMap.put("调度用时（分）", sendUseTimeMinute);
				}
				Double rescueTime = m.getRescueTime();
				if(!Func.isNull(rescueTime)) {
					elementMap.put("救援作业用时（分）", String.valueOf(rescueTime));
				}
				Double workMinute = m.getWorkMinute();
				if(!Func.isNull(workMinute)){
					elementMap.put("救援整体耗时（分）", String.valueOf(workMinute));
				}
				String planStatusDesc = m.getPlanStatusDesc();
				if(Func.isNotBlank(planStatusDesc)){
					elementMap.put("任务状态", planStatusDesc);
				}
				Boolean isInMaintain = m.getIsInMaintain();
				if(!Func.isNull(isInMaintain)){
					elementMap.put("救援梯是否在保", isInMaintain? "是" : "否");
				}
				Boolean isOutsource = m.getIsOutsource();
				if (!Func.isNull(isOutsource)){
					elementMap.put("救援梯是否外包", isOutsource? "是" : "否");
				}
				element.setFields(elementMap);
				records.add(element);
			}
			batchDTO.setRecords(records);
			// 3. 覆盖表格，并发送消息
			List<JSONObject> deleteObjects = feiShuDocumentService.commandQueryBatch(appToken, tableId, null);
			// 遍历并获取 jsonObjects 的 封装成 FeiShuBatchDTO 对象
			List<String> r = new ArrayList<>();
			deleteObjects.forEach(j -> r.add(j.getString("record_id")));
			FeiShuBatchDTO deleteFeiShuBatchDTO = new FeiShuBatchDTO();
			deleteFeiShuBatchDTO.setRecords(r);
			// 直接覆盖
			feiShuDocumentService.commandDeleteBatchLimit(appToken, tableId, deleteFeiShuBatchDTO);
			// 新增
			String result = feiShuDocumentService.commandAddBatchLimit(appToken, tableId, batchDTO);
			result = "定时任务更新天雄救援故障仪表盘-救援工单明细表" + result;
			// 发送消息
			feiShuDocumentService.commandSendGroupMessage(appToken,tableId,result);
			XxlJobHelper.handleSuccess("定时任务更新天雄救援故障仪表盘-救援工单明细表-[执行]成功");
		}catch (Exception e){
			XxlJobHelper.handleSuccess("定时任务更新天雄救援故障仪表盘-救援工单明细表-[执行]失败"+e);
		}
	}

	/**
	 * 维修工单明细
	 */
	@XxlJob("galaxyRepairPlanDetailJobV2")
	public void galaxyRepairPlanDetailJobV2() {
		XxlJobHelper.handleSuccess("定时任务更新天雄救援故障仪表盘-维修工单明细表-[执行]开始");
		try{
			String appToken = FeiShuDocumentEnum.REPAIR_PLAN_DETAIL_V2.getAppToken();
			String tableId = FeiShuDocumentEnum.REPAIR_PLAN_DETAIL_V2.getTableId();
			List<Map<String,Object>> list = maintainMalfunctionWorkService.getBiWxPlanDetailListV2();
			FeiShuBatchDTO batchDTO = new FeiShuBatchDTO();
			List<FeiShuFieldsDTO> records = new ArrayList<>();
			if(Func.isNotEmpty(list)){
				list.forEach(e -> {
					FeiShuFieldsDTO element = new FeiShuFieldsDTO();
					element.setFields(e);
					records.add(element);
				});
			}
			batchDTO.setRecords(records);
			// 3. 覆盖表格，并发送消息
			List<JSONObject> deleteObjects = feiShuDocumentService.commandQueryBatch(appToken, tableId, null);
			// 遍历并获取 jsonObjects 的 封装成 FeiShuBatchDTO 对象
			List<String> r = new ArrayList<>();
			deleteObjects.forEach(j -> r.add(j.getString("record_id")));
			FeiShuBatchDTO deleteFeiShuBatchDTO = new FeiShuBatchDTO();
			deleteFeiShuBatchDTO.setRecords(r);
			// 直接覆盖
			feiShuDocumentService.commandDeleteBatchLimit(appToken, tableId, deleteFeiShuBatchDTO);
			// 新增
			String result = feiShuDocumentService.commandAddBatchLimit(appToken, tableId, batchDTO);
			result = "定时任务更新天雄救援故障仪表盘-维修工单明细表" + result;
			// 发送消息
			feiShuDocumentService.commandSendGroupMessage(appToken,tableId,result);
			XxlJobHelper.handleSuccess("定时任务更新天雄救援故障仪表盘-维修工单明细表-[执行]成功");
		}catch (Exception e){
			XxlJobHelper.handleSuccess("定时任务更新天雄救援故障仪表盘-维修工单明细表-[执行]失败"+e);
		}
	}

	/**
	 * 维修工单统计表
	 */
	@XxlJob("galaxyRepairPlanCountJobV2")
	public void galaxyRepairPlanCountJobV2() {
		XxlJobHelper.handleSuccess("定时任务更新天雄救援故障仪表盘-维修工单统计表-[执行]开始");
		try{
			String appToken = FeiShuDocumentEnum.REPAIR_PLAN_COUNT_V2.getAppToken();
			String tableId = FeiShuDocumentEnum.REPAIR_PLAN_COUNT_V2.getTableId();
			List<Map<String,Object>> list = maintainMalfunctionWorkService.galaxyRepairPlanCountJobV2();
			FeiShuBatchDTO batchDTO = new FeiShuBatchDTO();
			List<FeiShuFieldsDTO> records = new ArrayList<>();
			if(Func.isNotEmpty(list)){
				list.forEach(e -> {
					FeiShuFieldsDTO element = new FeiShuFieldsDTO();
					element.setFields(e);
					records.add(element);
				});
			}
			batchDTO.setRecords(records);
			// 3. 覆盖表格，并发送消息
			List<JSONObject> deleteObjects = feiShuDocumentService.commandQueryBatch(appToken, tableId, null);
			// 遍历并获取 jsonObjects 的 封装成 FeiShuBatchDTO 对象
			List<String> r = new ArrayList<>();
			deleteObjects.forEach(j -> r.add(j.getString("record_id")));
			FeiShuBatchDTO deleteFeiShuBatchDTO = new FeiShuBatchDTO();
			deleteFeiShuBatchDTO.setRecords(r);
			// 直接覆盖
			feiShuDocumentService.commandDeleteBatchLimit(appToken, tableId, deleteFeiShuBatchDTO);
			// 新增
			String result = feiShuDocumentService.commandAddBatchLimit(appToken, tableId, batchDTO);
			result = "定时任务更新天雄救援故障仪表盘-维修工单统计表" + result;
			// 发送消息
			feiShuDocumentService.commandSendGroupMessage(appToken,tableId,result);
			XxlJobHelper.handleSuccess("定时任务更新天雄救援故障仪表盘-维修工单统计表-[执行]成功");
		}catch (Exception e){
			XxlJobHelper.handleSuccess("定时任务更新天雄救援故障仪表盘-维修工单统计表-[执行]失败"+e);
		}
	}

	/**
	 * 救援工单明细表
	 */
	@XxlJob("galaxyRescuePlanDetailJobV2")
	public void galaxyRescuePlanDetailJobV2() {
		XxlJobHelper.handleSuccess("定时任务更新天雄救援故障仪表盘-救援工单明细表-[执行]开始");
		try{
			String appToken = FeiShuDocumentEnum.RESCUE_PLAN_DETAIL_V2.getAppToken();
			String tableId = FeiShuDocumentEnum.RESCUE_PLAN_DETAIL_V2.getTableId();
			List<Map<String,Object>> list = rescueService.getBiRescuePlanDetailListV2();
			FeiShuBatchDTO batchDTO = new FeiShuBatchDTO();
			List<FeiShuFieldsDTO> records = new ArrayList<>();
			if(Func.isNotEmpty(list)){
				list.forEach(e -> {
					FeiShuFieldsDTO element = new FeiShuFieldsDTO();
					element.setFields(e);
					records.add(element);
				});
			}
			batchDTO.setRecords(records);
			// 3. 覆盖表格，并发送消息
			List<JSONObject> deleteObjects = feiShuDocumentService.commandQueryBatch(appToken, tableId, null);
			// 遍历并获取 jsonObjects 的 封装成 FeiShuBatchDTO 对象
			List<String> r = new ArrayList<>();
			deleteObjects.forEach(j -> r.add(j.getString("record_id")));
			FeiShuBatchDTO deleteFeiShuBatchDTO = new FeiShuBatchDTO();
			deleteFeiShuBatchDTO.setRecords(r);
			// 直接覆盖
			feiShuDocumentService.commandDeleteBatchLimit(appToken, tableId, deleteFeiShuBatchDTO);
			// 新增
			String result = feiShuDocumentService.commandAddBatchLimit(appToken, tableId, batchDTO);
			result = "定时任务更新天雄救援故障仪表盘-救援工单明细表" + result;
			// 发送消息
			feiShuDocumentService.commandSendGroupMessage(appToken,tableId,result);
			XxlJobHelper.handleSuccess("定时任务更新天雄救援故障仪表盘-救援工单明细表-[执行]成功");
		}catch (Exception e){
			XxlJobHelper.handleSuccess("定时任务更新天雄救援故障仪表盘-救援工单明细表-[执行]失败"+e);
		}
	}

	/**
	 * 救援工单统计表
	 */
	@XxlJob("galaxyRescuePlanCountJobV2")
	public void galaxyRescuePlanCountJobV2() {
		XxlJobHelper.handleSuccess("定时任务更新天雄救援故障仪表盘-救援工单统计表-[执行]开始");
		try{
			String appToken = FeiShuDocumentEnum.RESCUE_PLAN_COUNT_V2.getAppToken();
			String tableId = FeiShuDocumentEnum.RESCUE_PLAN_COUNT_V2.getTableId();
			List<Map<String,Object>> list = rescueService.getBiRescuePlanCountListV2();
			FeiShuBatchDTO batchDTO = new FeiShuBatchDTO();
			List<FeiShuFieldsDTO> records = new ArrayList<>();
			if(Func.isNotEmpty(list)){
				list.forEach(e -> {
					FeiShuFieldsDTO element = new FeiShuFieldsDTO();
					element.setFields(e);
					records.add(element);
				});
			}
			batchDTO.setRecords(records);
			// 3. 覆盖表格，并发送消息
			List<JSONObject> deleteObjects = feiShuDocumentService.commandQueryBatch(appToken, tableId, null);
			// 遍历并获取 jsonObjects 的 封装成 FeiShuBatchDTO 对象
			List<String> r = new ArrayList<>();
			deleteObjects.forEach(j -> r.add(j.getString("record_id")));
			FeiShuBatchDTO deleteFeiShuBatchDTO = new FeiShuBatchDTO();
			deleteFeiShuBatchDTO.setRecords(r);
			// 直接覆盖
			feiShuDocumentService.commandDeleteBatchLimit(appToken, tableId, deleteFeiShuBatchDTO);
			// 新增
			String result = feiShuDocumentService.commandAddBatchLimit(appToken, tableId, batchDTO);
			result = "定时任务更新天雄救援故障仪表盘-救援工单统计表" + result;
			// 发送消息
			feiShuDocumentService.commandSendGroupMessage(appToken,tableId,result);
			XxlJobHelper.handleSuccess("定时任务更新天雄救援故障仪表盘-救援工单统计表-[执行]成功");
		}catch (Exception e){
			XxlJobHelper.handleSuccess("定时任务更新天雄救援故障仪表盘-救援工单统计表-[执行]失败"+e);
		}
	}

	/**
	 * 获取星期区间内日期描述
	 * @param date 日期
	 * @return 星期描述: yyyy/MM/dd~yyyy/MM/dd
	 */
	private String getWeekDesc(Date date){
		// 获取日期所在这一周的第一天的日期并格式化
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		calendar.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
		Date firstDayOfWeek = calendar.getTime();
		String firstDayOfWeekDesc = DateUtil.format(firstDayOfWeek, "yyyy/MM/dd");
		// 获取日期所在这一周的最后一天的日期并格式化
		calendar.add(Calendar.DAY_OF_WEEK, 6);
		Date lastDayOfWeek = calendar.getTime();
		String lastDayOfWeekDesc = DateUtil.format(lastDayOfWeek, "yyyy/MM/dd");
		// 组装星期描述
		return firstDayOfWeekDesc + "~" + lastDayOfWeekDesc;
	}

	/**
	 * 获取日期对应这一年的所属月份,以及年
	 */
	private String getMonthDesc(Date date){
		return DateUtil.format(date, "yyyy/MM");
	}

	private double getRounder(double value){
		return Math.round(value * 100.0) / 100.0;
	}

	private Date getRangeStartDate(Date startDate, Integer dateType){
		if (new Integer(2).equals(dateType)) {
			startDate = DateUtil.beginOfWeek(startDate);

		} else if (new Integer(3).equals(dateType)) {
			startDate = DateUtil.beginOfMonth(startDate);
		}
		return startDate;
	}

	private Date getRangeEndDate(Date endDate, Integer dateType){
		if (new Integer(2).equals(dateType)) {
			endDate = DateUtil.endOfWeek(endDate);
		} else if (new Integer(3).equals(dateType)) {
			endDate = DateUtil.endOfMonth(endDate);
		}
		return endDate;
	}

	private List<String> getDateList(Date startDate, Date endDate, Integer dateType){
		List<String> dateList = new ArrayList<>(32);
		if (dateType.equals(2)) {
			startDate = DateUtil.beginOfWeek(startDate);
			endDate = DateUtil.endOfWeek(endDate);
			// 周
			List<DateTime> rangeDate = DateUtil.rangeToList(startDate, endDate, DateField.DAY_OF_YEAR);
			rangeDate.forEach(date -> {
				String weekDate = String.format("%s~%s", DateUtil.format(DateUtil.beginOfWeek(date), "yyyy/MM/dd"), DateUtil.format(DateUtil.endOfWeek(date), "yyyy/MM/dd"));
				if (!dateList.contains(weekDate)) {
					dateList.add(weekDate);
				}
			});
		} else if (dateType.equals(3)) {
			startDate = DateUtil.beginOfMonth(startDate);
			endDate = DateUtil.endOfMonth(endDate);
			// 月
			List<DateTime> rangeDate = DateUtil.rangeToList(startDate, endDate, DateField.MONTH);
			rangeDate.forEach(date -> {
				String monthDate = DateUtil.format(date, "yyyy/MM");
				if (!dateList.contains(monthDate)) {
					dateList.add(monthDate);
				}
			});
		}
		Collections.reverse(dateList);
		return dateList;
	}

	private List<BILarkRescueHealthVO> getExportData(Date startDate, Date endDate, Integer dateType){
		List<BILarkRescueCountSourceVO> getGalaxyRescueResource = biService.getGalaxyRescueResource(startDate, endDate);
		Map<String, List<BILarkRescueCountSourceVO>> dateGroup;
		if (new Integer(1).equals(dateType)) {
			dateGroup = getGalaxyRescueResource.stream().collect(Collectors.groupingBy(e -> DateUtil.format(e.getCreateTime(), "yyyy/MM/dd")));
		} else if (new Integer(2).equals(dateType)) {
			dateGroup = getGalaxyRescueResource.stream().collect(Collectors.groupingBy(t -> String.format("%s~%s", DateUtil.format(DateUtil.beginOfWeek(t.getCreateTime()), "yyyy/MM/dd"), DateUtil.format(DateUtil.endOfWeek(t.getCreateTime()), "yyyy/MM/dd"))));
		} else {
			dateGroup = getGalaxyRescueResource.stream().collect(Collectors.groupingBy(t -> String.format("%s", DateUtil.format(t.getCreateTime(), "yyyy/MM"))));
		}
		if(Func.isEmpty(dateGroup)){
			log.warn("该查询范围下无数据，无需导出");
		}
		// 分组时间按分组倒序/正序
		List<String> dateList = getDateList(startDate, endDate, dateType);
		List<BILarkRescueHealthVO> exportData = new ArrayList<>();
		dateList.forEach(d -> {
			if(dateGroup.containsKey(d)){
				List<BILarkRescueCountSourceVO> v = dateGroup.get(d);
				// 处理日期描述
				String dateDesc = null;
				Date rangeEndDate = null;
				int elevatorCount = 0;
				if(Func.isNotEmpty(v)){
					Date groupCreateTimeDemo = v.get(0).getCreateTime();
					rangeEndDate = getRangeEndDate(groupCreateTimeDemo, dateType);
					dateDesc = d;
				}
				// 根据 rangeEndDate 获取监控梯台数
				if(!Func.isNull(rangeEndDate)){
					// 2025-02-05 将监控梯台数修改成 在保非外包
					// 将rangeEndDate 改为 "yyyy-MM-dd" 格式
					String rangeEndDateFormat = DateUtil.format(rangeEndDate, "yyyy-MM-dd");
					// 将 rangeEndDateFormat 改成 date
					Date rangeEndDateParam = DateUtil.parse(rangeEndDateFormat);
					elevatorCount = maintainStatusDayService.countByRangeEndDate(rangeEndDateParam);
				}
				BILarkRescueHealthVO rescueHealthVO = new BILarkRescueHealthVO();
				rescueHealthVO.setGroupDateDesc(dateDesc);
				rescueHealthVO.setElevatorCount(elevatorCount);
				rescueHealthVO.setRescueCount(v.size());
				long onTimeCount = v.stream().filter(e -> new Integer(3).equals(e.getIsOverTime())).count();
				rescueHealthVO.setOnTimeCount((int) onTimeCount);
				rescueHealthVO.setLateCount(v.size() - (int) onTimeCount);
				exportData.add(rescueHealthVO);
			}
		});
		return exportData;
	}

	private void sendRescueHealthTableData(List<BILarkRescueHealthVO> exportData, String appToken, String tableId){
		if (Func.isNotEmpty(exportData)) {
			FeiShuBatchDTO batchDTO = new FeiShuBatchDTO();
			List<FeiShuFieldsDTO> records = new ArrayList<>();
			for (BILarkRescueHealthVO s : exportData) {
				FeiShuFieldsDTO element = new FeiShuFieldsDTO();
				Map<String, Object> elementMap = new HashMap<>(30);
				String groupDateDesc = s.getGroupDateDesc();
				if (Func.isNotBlank(groupDateDesc)) {
					elementMap.put("日期", s.getGroupDateDesc());
				}
				Integer elevatorCount = s.getElevatorCount();
				if (!Func.isNull(elevatorCount)) {
					elementMap.put("监控梯台数", elevatorCount);
				}
				Integer rescueCount = s.getRescueCount();
				if (!Func.isNull(rescueCount)) {
					elementMap.put("累计救援次数", rescueCount);
				}
				Integer onTimeCount = s.getOnTimeCount();
				if (!Func.isNull(onTimeCount)) {
					elementMap.put("准时到达救援次数", onTimeCount);
				}
				Integer lateCount = s.getLateCount();
				if (!Func.isNull(lateCount)) {
					elementMap.put("超项目指定时长到达次数", lateCount);
				}
				element.setFields(elementMap);
				records.add(element);
			}
			batchDTO.setRecords(records);
			// 3. 覆盖表格，并发送消息
//			List<JSONObject> deleteObjects = feiShuDocumentService.commandQueryBatch(appToken, tableId, null);
//			// 遍历并获取 jsonObjects 的 封装成 FeiShuBatchDTO 对象
//			List<String> r = new ArrayList<>();
//			deleteObjects.forEach(j -> r.add(j.getString("record_id")));
//			FeiShuBatchDTO deleteFeiShuBatchDTO = new FeiShuBatchDTO();
//			deleteFeiShuBatchDTO.setRecords(r);
//			// 直接覆盖
//			feiShuDocumentService.commandDeleteBatchLimit(appToken, tableId, deleteFeiShuBatchDTO);
//			// 新增
//			String result = feiShuDocumentService.commandAddBatchLimit(appToken, tableId, batchDTO);
			String result = "定时任务更新天雄救援故障仪表盘-救援健康指标表" + feiShuDocumentService.commandCompareUpdateBatch(appToken, tableId, batchDTO, "日期");
			// 发送消息
			feiShuDocumentService.commandSendGroupMessage(appToken, tableId, result);
		}
	}

	private void sendRepairHealthTableData(List<Map<String, String>> mapList, String appToken, String tableId){
		if(Func.isNotEmpty(mapList)){
			FeiShuBatchDTO batchDTO = new FeiShuBatchDTO();
			List<FeiShuFieldsDTO> records = new ArrayList<>();
			for (Map<String, String> m : mapList) {
				FeiShuFieldsDTO element = new FeiShuFieldsDTO();
				Map<String, Object> elementMap = new HashMap<>(30);
				if(m.containsKey("日期")){
					elementMap.put("日期", m.get("日期"));
				}
				if(m.containsKey("监控梯台数")){
					String s = m.get("监控梯台数");
					elementMap.put("监控梯台数", new Integer(s));
				}
				if(m.containsKey("故障维修工单数")){
					String s = m.get("故障维修工单数");
					elementMap.put("故障维修工单数", new Integer(s));
				}
				if(m.containsKey("停梯故障维修工单数")){
					String s = m.get("停梯故障维修工单数");
					elementMap.put("停梯故障维修工单数", new Integer(s));
				}
				if(m.containsKey("维修工单关闭总时长")){
					String s = m.get("维修工单关闭总时长");
					elementMap.put("维修工单关闭总时长", new Double(s));
				}
				if(m.containsKey("停梯超3h维修工单数")){
					String s = m.get("停梯超3h维修工单数");
					elementMap.put("停梯超3h维修工单数", new Double(s));
				}
				if(m.containsKey("参与维修员人数")){
					String s = m.get("参与维修员人数");
					elementMap.put("参与维修员人数", new Double(s));
				}
				if(m.containsKey("参与保养员人数")){
					String s = m.get("参与保养员人数");
					elementMap.put("参与保养员人数", new Double(s));
				}
				if(m.containsKey("参与维修人次")){
					String s = m.get("参与维修人次");
					elementMap.put("参与维修人次", new Double(s));
				}
				if(m.containsKey("2人及以上参与工单数")){
					String s = m.get("2人及以上参与工单数");
					elementMap.put("2人及以上参与工单数", new Double(s));
				}
				if(m.containsKey("故障关闭时长中位数")){
					String s = m.get("故障关闭时长中位数");
					elementMap.put("故障关闭时长中位数", new Double(s));
				}
				if(m.containsKey("维修工单到场总时长")){
					String s = m.get("维修工单到场总时长");
					elementMap.put("维修工单到场总时长", new Double(s));
				}
				if(m.containsKey("故障到场时长中位数")){
					String s = m.get("故障到场时长中位数");
					elementMap.put("故障到场时长中位数", new Double(s));
				}
				if(m.containsKey("维修工单作业总时长")){
					String s = m.get("维修工单作业总时长");
					elementMap.put("维修工单作业总时长", new Double(s));
				}
				if(m.containsKey("故障作业时长中位数")){
					String s = m.get("故障作业时长中位数");
					elementMap.put("故障作业时长中位数", new Double(s));
				}

				element.setFields(elementMap);
				records.add(element);
			}
			batchDTO.setRecords(records);
			// 3. 覆盖表格，并发送消息
//			List<JSONObject> deleteObjects = feiShuDocumentService.commandQueryBatch(appToken, tableId, null);
//			// 遍历并获取 jsonObjects 的 封装成 FeiShuBatchDTO 对象
//			List<String> r = new ArrayList<>();
//			deleteObjects.forEach(j -> r.add(j.getString("record_id")));
//			FeiShuBatchDTO deleteFeiShuBatchDTO = new FeiShuBatchDTO();
//			deleteFeiShuBatchDTO.setRecords(r);
//			// 直接覆盖
//			feiShuDocumentService.commandDeleteBatchLimit(appToken, tableId, deleteFeiShuBatchDTO);
//			// 新增
//			String result = feiShuDocumentService.commandAddBatchLimit(appToken, tableId, batchDTO);
//			result = "定时任务更新天雄救援故障仪表盘-故障健康指标表" + result;
			String result = "定时任务更新天雄救援故障仪表盘-故障健康指标表" + feiShuDocumentService.commandCompareUpdateBatch(appToken, tableId, batchDTO, "日期");
			// 发送消息
			feiShuDocumentService.commandSendGroupMessage(appToken, tableId, result);
		}
	}
}
